﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

#include "ILevel.h"
#include "IElement.h"
#include "IPlane.h"
#include "NdbObjectSchematic.h"
#include "ILevelHeaderBehavior.h"
#include "NewLevelBehaviors.h"
#include "SurfaceAndTerminals.h"
#include "IElementDeletionComponent.h"
#include "DbDataSchema.h"
#include "RegenDataSchema.h"

namespace gcmp {

    class IElement;
    class IDocument;
    class IGraphicsElementShape;
    class Matrix4d;
    class IModelView;
    class MoveContext;
    class Type;
    class UniIdentity;
    class Vector3d;
    class ILevelType;

    class GBMP_MODEL_EXPORT NewLevel : public NdbObjectSchematic, public ILevel
    {
    private:
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(gcmp, NewLevel, gcmp::NdbObjectSchematic, E9602523 - 546E-4EBD - 9AF7 - 3EA5144186EF, gbmpmodel, gcmp::ILevel)
            // IExternalObject所需的属性， 暂时都用默认的
            DATA_TRANSIENT(IElement*, pOwnerElement)
            // Level相关的属性，RangeU和RangeV暂时使用， 后面会替换成和轴网一样的范围框
            DATA_REGEN_OVERRIDE(OwnerPtr<IPlane>, ReferencePlane)
            DATA(TerminalParams, GlobalTerminalParams)                               // 全局边界参数域
            UMAP_DATA(ElementId, TerminalParams, ElementIdHash, LocalTerminalParams) // 视图重载边界参数域
            DATA(Bool, IsShowFromLeftToRight)  // 标记是否从左到右显示 
            DATA(OwnerPtr<ILevelHeaderBehavior>, LevelHeaderBehavior)
            DATA(ElementId, buildingId)          // 单体的Id
            ARR_DATA(ElementId, PlanViewIds)    // 关联的平面视图
            ARR_DATA(ElementId, CeilingViewIds) // 关联的天花板视图
        DBOBJECT_DATA_END
#pragma region IExternalObject接口
    public:
        virtual bool SetOwnerElement(IElement* pOwnerElement) override;
        virtual IElement* GetOwnerElement() override { return m_pOwnerElement; }
        virtual const IElement* GetOwnerElement() const override { return m_pOwnerElement; }

        virtual NdbObject* GetTopOwnerObject() const override;
    public:
        virtual ~NewLevel() {}

#pragma endregion 基本属性

#pragma region 关联更新
        virtual void UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds) override;

        virtual void ReportParents(IElementParentReporter& reporter) const override;

#pragma endregion 关联更新

#pragma region 其他
        virtual bool FinishEditing() override;
#pragma endregion 其他

#pragma endregion IExternalObject接口

#pragma region ILevel接口
    public:
        // 标高的包围盒
        virtual Box3d GetBox() const override;

        virtual const ILevelType* GetLevelType() const override;
        // 标高高度
        virtual double GetElevation() const override;
        virtual bool SetElevation(double elevation) override;
        // 标高平面
        virtual const IPlane* GetReferencePlane() const override { return GetReferencePlane__().get(); }
        void SetReferencePlane(gcmp::OwnerPtr<gcmp::IPlane> plane) { SetReferencePlane__(TransferOwnership(plane)); MarkReferencePlaneRdId(); }

        virtual const ILevelHeaderBehavior* GetLevelHeaderBehavior() const override { return m_LevelHeaderBehavior.get(); }
        virtual ILevelHeaderBehavior* GetLevelHeaderBehavior() override { return m_LevelHeaderBehavior.get(); }
        virtual bool SetLevelHeaderBehavior(OwnerPtr<ILevelHeaderBehavior> opBehavior) override { SetLevelHeaderBehavior__(TransferOwnership(opBehavior)); return true; }

        virtual bool AddAssociatedPlanViewId(ElementId viewId) override;
        virtual bool AddAssociatedCeilingViewId(ElementId viewId) override;
        virtual std::vector<ElementId> GetAssociatedPlanViewIds() const override;
        virtual std::vector<ElementId> GetAssociatedCeilingViewIds() const override;

        virtual std::wstring GetName() const override;
#pragma endregion ILevel接口

    public:
        // 创建标高
        static NewLevel* Create(IDocument* pDoc, ElementId typeId, const std::wstring& name, const Vector3d& startPt, const Vector3d& endPt, const Vector3d& viewDir, const ElementId &buildingId, ElementCreationOptions eco);
        static NewLevel* Create(IDocument* pDoc, ElementId typeId, const LevelName& name, const Vector3d& startPt, const Vector3d& endPt, const Vector3d& viewDir, const ElementId &buildingId, ElementCreationOptions eco);

        virtual bool SetBuildingId(ElementId buildingId) override { SetbuildingId__(buildingId); return true; }
        virtual ElementId GetBuildingId() const override { return GetbuildingId__(); }
        virtual bool MoveAuxiliaryPoint(const IModelView* pModelView, const Vector3d newPoint, ElementId shapeHandleId) override;
        bool Translate(const IElementMoveContext& moveContext);
        void GetModelViewProjectLine(const IModelView* pModelView, Vector3d& start, Vector3d& end) const;

        static gcmp::UniIdentity GetImplementationUid();
    protected:
        // 创建Level GRep相关的函数， 后续需要改进
        OwnerPtr<IGraphicsElementShape> CreateLevelGrep(const IModelView* pModelView) const;
        OwnerPtr<IGraphicsNodeGroup> CreateLevelHeader(const Vector3d& symbolPos, const Vector3d& symbolDir, const Vector3d& texDir, double height, double viewScale) const;
        void GetLevelPlaneCorner(Vector3d& bottomLeft, Vector3d& bottomRight, Vector3d& topLeft, Vector3d& topRight) const;
        // 临时实验用
        bool IsShowFromLeftToRight() const { return GetIsShowFromLeftToRight__(); }
        void SetShowFromLeftToRight(bool isLeftToRight) { SetIsShowFromLeftToRight__(isLeftToRight); }
        const TerminalParams& GetGlobalTerminalParams() const { return GetGlobalTerminalParams__(); }
        double GetLevelPlaneLength() const;
        double GetLevelPlaneDepth() const;

        friend class NewLevelViewSpecificShapeComponent;
        friend class NewLevelShapeHandleBehavior;
        friend class NewLevelSnapComponent;

    protected:
        IDocument* GetDocument() const;
        ElementId GetOwnerElementId() const;
        IPlane* GetReferencePlaneFW() { return GetReferencePlaneFW__().get(); }
        Vector2d GetMidPoint() const;
    private:
        // 创建标高平面
        bool CreateReferencePlane(const Vector3d& startPt, const Vector3d& endPt, const Vector3d& viewDir, const Box3d& workspace);
        Box3d GetWorkspace(const IDocument* pDoc);

        // for debug
        OwnerPtr<IGraphicsElementShape> CreateLevelGrepIn3DView(const IModelView* pModelView) const;
    };

    class GBMP_MODEL_EXPORT NewLevelUtil
    {
    public:
        static std::set<std::pair<double, gcmp::ElementId>> GetAllLevelsFromLowToHigh(const gcmp::IDocument* pDoc);
    };
}// namespace gcmp

